
/*
 * Copyright (c) 2008 - 2009 NVIDIA Corporation.  All rights reserved.
 *
 * NVIDIA Corporation and its licensors retain all intellectual property and proprietary
 * rights in and to this software, related documentation and any modifications thereto.
 * Any use, reproduction, disclosure or distribution of this software and related
 * documentation without an express license agreement from NVIDIA Corporation is strictly
 * prohibited.
 *
 * TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THIS SOFTWARE IS PROVIDED *AS IS*
 * AND NVIDIA AND ITS SUPPLIERS DISCLAIM ALL WARRANTIES, EITHER EXPRESS OR IMPLIED,
 * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE.  IN NO EVENT SHALL NVIDIA OR ITS SUPPLIERS BE LIABLE FOR ANY
 * SPECIAL, INCIDENTAL, INDIRECT, OR CONSEQUENTIAL DAMAGES WHATSOEVER (INCLUDING, WITHOUT
 * LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF
 * BUSINESS INFORMATION, OR ANY OTHER PECUNIARY LOSS) ARISING OUT OF THE USE OF OR
 * INABILITY TO USE THIS SOFTWARE, EVEN IF NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGES
 */

#pragma once

#include <optixu/optixu_vector_types.h>
#include <optixu/optixu_math_stream.h>

using namespace optix;

rtDeclareVariable(float, lambdaMin, , );
rtDeclareVariable(float, lambdaMax, , );

rtBuffer<float, >              CIE_X, CIE_Y, CIE_Z;


struct SPD16
{
	float   lambdaMin, lambdaMax, delta;
	float samples[16];
};


typedef struct struct_BasicLight
{
#if defined(__cplusplus)
	typedef optix::float3 float3;
#endif

	float3 pos;
	SPD16 color;
	int    casts_shadow;
	int    padding;      // make this structure 32 bytes -- powers of two are your friend!
} BasicLight;

struct TriangleLight
{
#if defined(__cplusplus)
	typedef optix::float3 float3;
#endif
	float3 v1, v2, v3;
	float3 normal;
	SPD16 emission;
	int lgt_idx;
	int textured;
};

__device__ __inline__ float sample_spd(const SPD16& s, float lambda)
{
	if (lambda < s.lambdaMin || lambda > s.lambdaMax)
		return 0.f;
	float x = (lambda - s.lambdaMin) * (1.f / s.delta);
	int b0 = (int)floorf(x);
	int b1 = (int)min(b0 + 1, 16 - 1);
	float dx = x - b0;
	return lerp(dx, s.samples[b0], s.samples[b1]);
};

__device__ __inline__ SPD16 create_spd(float lambdaStart, float lambdaEnd, float samples[16]){
	SPD16 s;
	s.lambdaMin = lambdaStart;
	s.lambdaMax = lambdaEnd;
	s.delta = (lambdaEnd - lambdaStart) / 16;
	for (int i = 0; i < 16; i++) {
		s.samples[i] = samples[i];
	}
	return s;
};

__device__ __inline__ float3 SPD2XYZ(const SPD16& s)
{
	float x = 0.f, y = 0.f, z = 0.f;
	float lambdaStart = s.lambdaMin;
	for (int i = 0; i < 16; i++) {
		float v = sample_spd(s, lambdaStart);
		x += v*CIE_X[i];
		y += v*CIE_Y[i];
		z += v*CIE_Z[i];
	}
	return make_float3(x, y, z) / 683.f;
};

__device__ __inline__ void XYZToRGB(const float3& xyz, float3& rgb) {
	rgb.x = 3.240479f*xyz.x - 1.537150f*xyz.y - 0.498535f*xyz.z;
	rgb.y = -0.969256f*xyz.x + 1.875991f*xyz.y + 0.041556f*xyz.z;
	rgb.z = 0.055648f*xyz.x - 0.204043f*xyz.y + 1.057311f*xyz.z;
}


__device__ __inline__ float sample_lambda(float u0)
{
	return lambdaMin + ((lambdaMax - lambdaMin))*u0;
}


